JavaScript ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ํจ์จ์ ์ผ๋ก ์คํธ๋ฆผ์ ์์ฑ, ๋ณํ ๋ฐ ๊ด๋ฆฌํ์ธ์. ๊ฒฌ๊ณ ํ ๋น๋๊ธฐ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ์ ์ํ ์ค์ ์์ ์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ดํด๋ณด์ธ์.
JavaScript ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ: ์คํธ๋ฆผ ์์ฑ ๋ฐ ๊ด๋ฆฌ ๋ง์คํฐํ๊ธฐ
JavaScript์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์๋ ์ ๊ฑธ์ณ ํฌ๊ฒ ๋ฐ์ ํด ์์ต๋๋ค. ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ(Async Generators)์ ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ(Async Iterators)์ ๋์ ์ผ๋ก ๊ฐ๋ฐ์๋ค์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ๋ ๊ฐ๋ ฅํ ๋๊ตฌ๋ฅผ ์ป๊ฒ ๋์์ต๋๋ค. ์ด์ JavaScript ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ(Async Generator Helpers)๋ ์ด๋ฌํ ๊ธฐ๋ฅ์ ๋์ฑ ํฅ์์์ผ, ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์์ฑ, ๋ณํ ๋ฐ ๊ด๋ฆฌํ๋ ๋ ๊ฐ์ํ๋๊ณ ํํ๋ ฅ ์๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์ด ๊ฐ์ด๋์์๋ ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ์ ๊ธฐ๋ณธ ์ฌํญ์ ํ๊ตฌํ๊ณ , ๊ทธ ๊ธฐ๋ฅ์ ๋ํด ์์ธํ ์์๋ณด๋ฉฐ, ๋ช ํํ ์์ ๋ฅผ ํตํด ์ค์ ์ ์ธ ์ ์ฉ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
๋น๋๊ธฐ ์ ๋๋ ์ดํฐ์ ์ดํฐ๋ ์ดํฐ ์ดํดํ๊ธฐ
๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ์ ๋ํด ์์๋ณด๊ธฐ ์ ์, ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ์ ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
๋น๋๊ธฐ ์ ๋๋ ์ดํฐ
๋น๋๊ธฐ ์ ๋๋ ์ดํฐ๋ ์ผ์ ์ค์งํ๊ณ ์ฌ๊ฐํ ์ ์๋ ํจ์๋ก, ๋น๋๊ธฐ์ ์ผ๋ก ๊ฐ์ ์์ฑ(yield)ํฉ๋๋ค. ์ด๋ฅผ ํตํด ๋ฉ์ธ ์ค๋ ๋๋ฅผ ์ฐจ๋จํ์ง ์๊ณ ์๊ฐ์ ํ๋ฆ์ ๋ฐ๋ผ ๊ฐ์ ์ํ์ค๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ๋ async function* ๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ฌ ์ ์๋ฉ๋๋ค.
์์ :
async function* generateSequence(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // ๋น๋๊ธฐ ์์
์๋ฎฌ๋ ์ด์
yield i;
}
}
// ์ฌ์ฉ๋ฒ
const sequence = generateSequence(1, 5);
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ next() ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ ๊ฐ์ฒด์
๋๋ค. ์ด ๋ฉ์๋๋ ์ํ์ค์ ๋ค์ ๊ฐ์ ํฌํจํ๋ ๊ฐ์ฒด์ ์ํ์ค๊ฐ ์์ง๋์๋์ง๋ฅผ ๋ํ๋ด๋ done ์์ฑ์ ํฌํจํ๋ ํ๋ก๋ฏธ์ค(promise)๋ก ํด์๋ฉ๋๋ค. ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ for await...of ๋ฃจํ๋ฅผ ์ฌ์ฉํ์ฌ ์๋น๋ฉ๋๋ค.
์์ :
async function* generateSequence(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 500));
yield i;
}
}
async function consumeSequence() {
const sequence = generateSequence(1, 5);
for await (const value of sequence) {
console.log(value);
}
}
consumeSequence();
๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ ์๊ฐ
๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ๋ ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํ๋กํ ํ์ ์ ๊ธฐ๋ฅ์ ํ์ฅํ๋ ๋ฉ์๋ ์งํฉ์ ๋๋ค. ์ด๋ค์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์กฐ์ํ๋ ํธ๋ฆฌํ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ฌ ์ฝ๋๋ฅผ ๋ ์ฝ๊ธฐ ์ฝ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ข๊ฒ ๋ง๋ญ๋๋ค. ์ด๋ฌํ ํฌํผ๋ ํ์ํ ๋๋ง ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ์ง์ฐ(lazy) ๋ฐฉ์์ผ๋ก ์๋ํ๋ฏ๋ก ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ๊ฐ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค(JavaScript ํ๊ฒฝ ๋ฐ ํด๋ฆฌํ์ ๋ฐ๋ผ ๋ค๋ฆ):
mapfiltertakedropflatMapreducetoArrayforEach
๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ ์์ธ ํ๊ตฌ
1. `map()`
map() ํฌํผ๋ ์ ๊ณต๋ ํจ์๋ฅผ ์ ์ฉํ์ฌ ๋น๋๊ธฐ ์ํ์ค์ ๊ฐ ๊ฐ์ ๋ณํํฉ๋๋ค. ๋ณํ๋ ๊ฐ์ ์์ฑํ๋ ์๋ก์ด ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ๋ฅผ ๋ฐํํฉ๋๋ค.
๊ตฌ๋ฌธ:
asyncGenerator.map(callback)
์์ : ์ซ์ ์คํธ๋ฆผ์ ์ ๊ณฑ ๊ฐ์ผ๋ก ๋ณํํ๊ธฐ.
async function* generateNumbers(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 200));
yield i;
}
}
async function processNumbers() {
const numbers = generateNumbers(1, 5);
const squares = numbers.map(async (num) => {
await new Promise(resolve => setTimeout(resolve, 100)); // ๋น๋๊ธฐ ์์
์๋ฎฌ๋ ์ด์
return num * num;
});
for await (const square of squares) {
console.log(square);
}
}
processNumbers();
์ค์ ์ฌ์ฉ ์ฌ๋ก: ์ฌ๋ฌ API์์ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ ์ผ๊ด๋ ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณํํด์ผ ํ๋ ๊ฒฝ์ฐ๋ฅผ ์์ํด ๋ณด์ธ์. map()์ ์ฌ์ฉํ์ฌ ๊ฐ ์ฌ์ฉ์ ๊ฐ์ฒด์ ๋ณํ ํจ์๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ์ ์ฉํ ์ ์์ต๋๋ค.
async function* fetchUsersFromMultipleAPIs(apiEndpoints) {
for (const endpoint of apiEndpoints) {
const response = await fetch(endpoint);
const data = await response.json();
for (const user of data) {
yield user;
}
}
}
async function processUsers() {
const apiEndpoints = [
'https://api.example.com/users1',
'https://api.example.com/users2'
];
const users = fetchUsersFromMultipleAPIs(apiEndpoints);
const normalizedUsers = users.map(async (user) => {
// ์ฌ์ฉ์ ๋ฐ์ดํฐ ํ์ ์ ๊ทํ
return {
id: user.userId || user.id,
name: user.fullName || user.name,
email: user.emailAddress || user.email
};
});
for await (const normalizedUser of normalizedUsers) {
console.log(normalizedUser);
}
}
2. `filter()`
filter() ํฌํผ๋ ์๋ณธ ์ํ์ค์์ ์ ๊ณต๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ๊ฐ๋ง ์์ฑํ๋ ์๋ก์ด ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ๋ฅผ ์์ฑํฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ฒฐ๊ณผ ์คํธ๋ฆผ์ ๊ฐ์ ์ ํ์ ์ผ๋ก ํฌํจํ ์ ์์ต๋๋ค.
๊ตฌ๋ฌธ:
asyncGenerator.filter(callback)
์์ : ์ซ์ ์คํธ๋ฆผ์์ ์ง์๋ง ํฌํจํ๋๋ก ํํฐ๋งํ๊ธฐ.
async function* generateNumbers(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 200));
yield i;
}
}
async function processNumbers() {
const numbers = generateNumbers(1, 10);
const evenNumbers = numbers.filter(async (num) => {
await new Promise(resolve => setTimeout(resolve, 100));
return num % 2 === 0;
});
for await (const evenNumber of evenNumbers) {
console.log(evenNumber);
}
}
processNumbers();
์ค์ ์ฌ์ฉ ์ฌ๋ก: ๋ก๊ทธ ํญ๋ชฉ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ๊ณ ์ฌ๊ฐ๋ ์์ค์ ๋ฐ๋ผ ํญ๋ชฉ์ ํํฐ๋งํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ค๋ฅ ๋ฐ ๊ฒฝ๊ณ ๋ง ์ฒ๋ฆฌํฉ๋๋ค.
async function* readLogFile(filePath) {
// ๋น๋๊ธฐ์ ์ผ๋ก ๋ก๊ทธ ํ์ผ์ ํ ์ค์ฉ ์ฝ๋ ๊ฒ์ ์๋ฎฌ๋ ์ด์
const logEntries = [
{ timestamp: '...', level: 'INFO', message: '...' },
{ timestamp: '...', level: 'ERROR', message: '...' },
{ timestamp: '...', level: 'WARNING', message: '...' },
{ timestamp: '...', level: 'INFO', message: '...' },
{ timestamp: '...', level: 'ERROR', message: '...' }
];
for (const entry of logEntries) {
await new Promise(resolve => setTimeout(resolve, 50));
yield entry;
}
}
async function processLogs() {
const logEntries = readLogFile('path/to/log/file.log');
const errorAndWarningLogs = logEntries.filter(async (entry) => {
return entry.level === 'ERROR' || entry.level === 'WARNING';
});
for await (const log of errorAndWarningLogs) {
console.log(log);
}
}
3. `take()`
take() ํฌํผ๋ ์๋ณธ ์ํ์ค์์ ์ฒ์ n๊ฐ์ ๊ฐ๋ง ์์ฑํ๋ ์๋ก์ด ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ๋ฅผ ์์ฑํฉ๋๋ค. ์ ์ฌ์ ์ผ๋ก ๋ฌดํํ๊ฑฐ๋ ๋งค์ฐ ํฐ ์คํธ๋ฆผ์์ ์ฒ๋ฆฌ๋๋ ํญ๋ชฉ ์๋ฅผ ์ ํํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
๊ตฌ๋ฌธ:
asyncGenerator.take(n)
์์ : ์ซ์ ์คํธ๋ฆผ์์ ์ฒ์ 3๊ฐ์ ์ซ์ ๊ฐ์ ธ์ค๊ธฐ.
async function* generateNumbers(start) {
let i = start;
while (true) {
await new Promise(resolve => setTimeout(resolve, 200));
yield i++;
}
}
async function processNumbers() {
const numbers = generateNumbers(1);
const firstThree = numbers.take(3);
for await (const num of firstThree) {
console.log(num);
}
}
processNumbers();
์ค์ ์ฌ์ฉ ์ฌ๋ก: ๋น๋๊ธฐ ๊ฒ์ API์์ ์์ 5๊ฐ์ ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ํ์ํฉ๋๋ค.
async function* search(query) {
// API์์ ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ ์๋ฎฌ๋ ์ด์
const results = [
{ title: 'Result 1', url: '...' },
{ title: 'Result 2', url: '...' },
{ title: 'Result 3', url: '...' },
{ title: 'Result 4', url: '...' },
{ title: 'Result 5', url: '...' },
{ title: 'Result 6', url: '...' }
];
for (const result of results) {
await new Promise(resolve => setTimeout(resolve, 100));
yield result;
}
}
async function displayTopSearchResults(query) {
const searchResults = search(query);
const top5Results = searchResults.take(5);
for await (const result of top5Results) {
console.log(result);
}
}
4. `drop()`
drop() ํฌํผ๋ ์๋ณธ ์ํ์ค์์ ์ฒ์ n๊ฐ์ ๊ฐ์ ๊ฑด๋๋ฐ๊ณ ๋๋จธ์ง ๊ฐ์ ์์ฑํ๋ ์๋ก์ด ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ๋ฅผ ์์ฑํฉ๋๋ค. ์ด๋ take()์ ๋ฐ๋์ด๋ฉฐ ์คํธ๋ฆผ์ ์ด๊ธฐ ๋ถ๋ถ์ ๋ฌด์ํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
๊ตฌ๋ฌธ:
asyncGenerator.drop(n)
์์ : ์ซ์ ์คํธ๋ฆผ์์ ์ฒ์ 2๊ฐ์ ์ซ์ ๋ฒ๋ฆฌ๊ธฐ.
async function* generateNumbers(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 200));
yield i;
}
}
async function processNumbers() {
const numbers = generateNumbers(1, 5);
const remainingNumbers = numbers.drop(2);
for await (const num of remainingNumbers) {
console.log(num);
}
}
processNumbers();
์ค์ ์ฌ์ฉ ์ฌ๋ก: API์์ ๊ฒ์๋ ๋๊ท๋ชจ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ํ์ด์ง๋ค์ด์ ํ ๋ ์ด๋ฏธ ํ์๋ ๊ฒฐ๊ณผ๋ฅผ ๊ฑด๋๋๋๋ค.
async function* fetchData(url, pageSize, pageNumber) {
const offset = (pageNumber - 1) * pageSize;
// ์คํ์
์ผ๋ก ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์๋ฎฌ๋ ์ด์
const data = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' },
{ id: 4, name: 'Item 4' },
{ id: 5, name: 'Item 5' },
{ id: 6, name: 'Item 6' },
{ id: 7, name: 'Item 7' },
{ id: 8, name: 'Item 8' }
];
const pageData = data.slice(offset, offset + pageSize);
for (const item of pageData) {
await new Promise(resolve => setTimeout(resolve, 100));
yield item;
}
}
async function displayPage(pageNumber) {
const pageSize = 3;
const allData = fetchData('api/data', pageSize, pageNumber);
const page = allData.drop((pageNumber - 1) * pageSize); // ์ด์ ํ์ด์ง์ ํญ๋ชฉ ๊ฑด๋๋ฐ๊ธฐ
const results = page.take(pageSize);
for await (const item of results) {
console.log(item);
}
}
// ์ฌ์ฉ ์์
displayPage(2);
5. `flatMap()`
flatMap() ํฌํผ๋ ๋น๋๊ธฐ ์ดํฐ๋ฌ๋ธ(Async Iterable)์ ๋ฐํํ๋ ํจ์๋ฅผ ์ ์ฉํ์ฌ ๋น๋๊ธฐ ์ํ์ค์ ๊ฐ ๊ฐ์ ๋ณํํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๊ฒฐ๊ณผ๋ก ๋์จ ๋น๋๊ธฐ ์ดํฐ๋ฌ๋ธ์ ๋จ์ผ ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ๋ก ํํํํฉ๋๋ค. ์ด๋ ๊ฐ ๊ฐ์ ๊ฐ์ ์คํธ๋ฆผ์ผ๋ก ๋ณํํ ๋ค์ ํด๋น ์คํธ๋ฆผ๋ค์ ๊ฒฐํฉํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
๊ตฌ๋ฌธ:
asyncGenerator.flatMap(callback)
์์ : ๋ฌธ์ฅ ์คํธ๋ฆผ์ ๋จ์ด ์คํธ๋ฆผ์ผ๋ก ๋ณํํ๊ธฐ.
async function* generateSentences() {
const sentences = [
'This is the first sentence.',
'This is the second sentence.',
'This is the third sentence.'
];
for (const sentence of sentences) {
await new Promise(resolve => setTimeout(resolve, 200));
yield sentence;
}
}
async function* stringToWords(sentence) {
const words = sentence.split(' ');
for (const word of words) {
await new Promise(resolve => setTimeout(resolve, 50));
yield word;
}
}
async function processSentences() {
const sentences = generateSentences();
const words = sentences.flatMap(async (sentence) => {
return stringToWords(sentence);
});
for await (const word of words) {
console.log(word);
}
}
processSentences();
์ค์ ์ฌ์ฉ ์ฌ๋ก: ์ฌ๋ฌ ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ์ ๋ํ ๋๊ธ์ ๊ฐ์ ธ์ ์ฒ๋ฆฌ๋ฅผ ์ํด ๋จ์ผ ์คํธ๋ฆผ์ผ๋ก ๊ฒฐํฉํฉ๋๋ค.
async function* fetchBlogPostIds() {
const blogPostIds = [1, 2, 3]; // API์์ ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ ID๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ ์๋ฎฌ๋ ์ด์
for (const id of blogPostIds) {
await new Promise(resolve => setTimeout(resolve, 100));
yield id;
}
}
async function* fetchCommentsForPost(postId) {
// API์์ ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ์ ๋๊ธ์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ์๋ฎฌ๋ ์ด์
const comments = [
{ postId: postId, text: `Comment 1 for post ${postId}` },
{ postId: postId, text: `Comment 2 for post ${postId}` }
];
for (const comment of comments) {
await new Promise(resolve => setTimeout(resolve, 50));
yield comment;
}
}
async function processComments() {
const postIds = fetchBlogPostIds();
const allComments = postIds.flatMap(async (postId) => {
return fetchCommentsForPost(postId);
});
for await (const comment of allComments) {
console.log(comment);
}
}
6. `reduce()`
reduce() ํฌํผ๋ ๋์ฐ๊ธฐ(accumulator)์ ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ์ ๊ฐ ๊ฐ(์ผ์ชฝ์์ ์ค๋ฅธ์ชฝ์ผ๋ก)์ ๋ํด ํจ์๋ฅผ ์ ์ฉํ์ฌ ๋จ์ผ ๊ฐ์ผ๋ก ์ค์
๋๋ค. ์ด๋ ๋น๋๊ธฐ ์คํธ๋ฆผ์์ ๋ฐ์ดํฐ๋ฅผ ์ง๊ณํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
๊ตฌ๋ฌธ:
asyncGenerator.reduce(callback, initialValue)
์์ : ์คํธ๋ฆผ์ ์๋ ์ซ์์ ํฉ๊ณ ๊ณ์ฐํ๊ธฐ.
async function* generateNumbers(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 200));
yield i;
}
}
async function processNumbers() {
const numbers = generateNumbers(1, 5);
const sum = await numbers.reduce(async (accumulator, num) => {
await new Promise(resolve => setTimeout(resolve, 100));
return accumulator + num;
}, 0);
console.log('Sum:', sum);
}
processNumbers();
์ค์ ์ฌ์ฉ ์ฌ๋ก: ์ผ๋ จ์ API ํธ์ถ์ ๋ํ ํ๊ท ์๋ต ์๊ฐ ๊ณ์ฐํ๊ธฐ.
async function* fetchResponseTimes(apiEndpoints) {
for (const endpoint of apiEndpoints) {
const startTime = Date.now();
try {
await fetch(endpoint);
const endTime = Date.now();
const responseTime = endTime - startTime;
await new Promise(resolve => setTimeout(resolve, 50));
yield responseTime;
} catch (error) {
console.error(`Error fetching ${endpoint}: ${error}`);
yield 0; // ๋๋ ์ค๋ฅ๋ฅผ ์ ์ ํ๊ฒ ์ฒ๋ฆฌ
}
}
}
async function calculateAverageResponseTime() {
const apiEndpoints = [
'https://api.example.com/endpoint1',
'https://api.example.com/endpoint2',
'https://api.example.com/endpoint3'
];
const responseTimes = fetchResponseTimes(apiEndpoints);
let count = 0;
const sum = await responseTimes.reduce(async (accumulator, time) => {
count++;
return accumulator + time;
}, 0);
const average = count > 0 ? sum / count : 0;
console.log(`Average response time: ${average} ms`);
}
7. `toArray()`
toArray() ํฌํผ๋ ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ๋ฅผ ์๋นํ๊ณ ์ ๋๋ ์ดํฐ๊ฐ ์์ฑํ ๋ชจ๋ ๊ฐ์ ํฌํจํ๋ ๋ฐฐ์ด๋ก ํด์๋๋ ํ๋ก๋ฏธ์ค๋ฅผ ๋ฐํํฉ๋๋ค. ์คํธ๋ฆผ์ ๋ชจ๋ ๊ฐ์ ์ถ๊ฐ ์ฒ๋ฆฌ๋ฅผ ์ํด ๋จ์ผ ๋ฐฐ์ด๋ก ์์งํด์ผ ํ ๋ ์ ์ฉํฉ๋๋ค.
๊ตฌ๋ฌธ:
asyncGenerator.toArray()
์์ : ์คํธ๋ฆผ์ ์ซ์๋ค์ ๋ฐฐ์ด๋ก ์์งํ๊ธฐ.
async function* generateNumbers(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 200));
yield i;
}
}
async function processNumbers() {
const numbers = generateNumbers(1, 5);
const numberArray = await numbers.toArray();
console.log('Number Array:', numberArray);
}
processNumbers();
์ค์ ์ฌ์ฉ ์ฌ๋ก: ํ์ด์ง๋ค์ด์ ๋ API์ ๋ชจ๋ ํญ๋ชฉ์ ์์งํ์ฌ ํด๋ผ์ด์ธํธ ์ธก ํํฐ๋ง ๋๋ ์ ๋ ฌ์ ์ํด ๋จ์ผ ๋ฐฐ์ด๋ก ๋ง๋ญ๋๋ค.
async function* fetchAllItems(apiEndpoint) {
let pageNumber = 1;
const pageSize = 100; // API์ ํ์ด์ง๋ค์ด์
์ ํ์ ๋ฐ๋ผ ์กฐ์
while (true) {
const url = `${apiEndpoint}?page=${pageNumber}&pageSize=${pageSize}`;
const response = await fetch(url);
const data = await response.json();
if (!data || data.length === 0) {
break; // ๋ ์ด์ ๋ฐ์ดํฐ ์์
}
for (const item of data) {
await new Promise(resolve => setTimeout(resolve, 50));
yield item;
}
pageNumber++;
}
}
async function processAllItems() {
const apiEndpoint = 'https://api.example.com/items';
const allItems = fetchAllItems(apiEndpoint);
const itemsArray = await allItems.toArray();
console.log(`Fetched ${itemsArray.length} items.`);
// `itemsArray`์ ๋ํด ์ถ๊ฐ์ ์ธ ์ฒ๋ฆฌ๋ฅผ ์ํํ ์ ์์ต๋๋ค
}
8. `forEach()`
forEach() ํฌํผ๋ ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ์ ๊ฐ ๊ฐ์ ๋ํด ์ ๊ณต๋ ํจ์๋ฅผ ํ ๋ฒ์ฉ ์คํํฉ๋๋ค. ๋ค๋ฅธ ํฌํผ์ ๋ฌ๋ฆฌ forEach()๋ ์๋ก์ด ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ๋ฅผ ๋ฐํํ์ง ์์ต๋๋ค. ๊ฐ ๊ฐ์ ๋ํ ๋ถ์ ํจ๊ณผ(side effects)๋ฅผ ์ํํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
๊ตฌ๋ฌธ:
asyncGenerator.forEach(callback)
์์ : ์คํธ๋ฆผ์ ๊ฐ ์ซ์๋ฅผ ์ฝ์์ ๊ธฐ๋กํ๊ธฐ.
async function* generateNumbers(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 200));
yield i;
}
}
async function processNumbers() {
const numbers = generateNumbers(1, 5);
await numbers.forEach(async (num) => {
await new Promise(resolve => setTimeout(resolve, 100));
console.log('Number:', num);
});
}
processNumbers();
์ค์ ์ฌ์ฉ ์ฌ๋ก: ์คํธ๋ฆผ์์ ๋ฐ์ดํฐ๊ฐ ์ฒ๋ฆฌ๋ ๋ ์ฌ์ฉ์ ์ธํฐํ์ด์ค์ ์ค์๊ฐ ์ ๋ฐ์ดํธ๋ฅผ ๋ณด๋ ๋๋ค.
async function* fetchRealTimeData(dataSource) {
// ์ค์๊ฐ ๋ฐ์ดํฐ(์: ์ฃผ๊ฐ)๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ ์๋ฎฌ๋ ์ด์
ํฉ๋๋ค.
const dataStream = [
{ timestamp: new Date(), price: 100 },
{ timestamp: new Date(), price: 101 },
{ timestamp: new Date(), price: 102 }
];
for (const dataPoint of dataStream) {
await new Promise(resolve => setTimeout(resolve, 500));
yield dataPoint;
}
}
async function updateUI() {
const realTimeData = fetchRealTimeData('stock-api');
await realTimeData.forEach(async (data) => {
// UI ์
๋ฐ์ดํธ ์๋ฎฌ๋ ์ด์
await new Promise(resolve => setTimeout(resolve, 100));
console.log(`Updating UI with data: ${JSON.stringify(data)}`);
// ์ค์ UI๋ฅผ ์
๋ฐ์ดํธํ๋ ์ฝ๋๋ ์ฌ๊ธฐ์ ์์ฑ๋ฉ๋๋ค.
});
}
๋ณต์กํ ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์ ์ํ ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ ๊ฒฐํฉํ๊ธฐ
๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ์ ์ง์ ํ ํ์ ๋ณต์กํ ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์ ๋ง๋ค๊ธฐ ์ํด ํจ๊ป ์ฐ๊ฒฐ๋ ์ ์๋ค๋ ์ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ๋น๋๊ธฐ ์คํธ๋ฆผ์ ๋ํด ์ฌ๋ฌ ๋ณํ ๋ฐ ์์ ์ ๊ฐ๊ฒฐํ๊ณ ์ฝ๊ธฐ ์ฌ์ด ๋ฐฉ์์ผ๋ก ์ํํ ์ ์์ต๋๋ค.
์์ : ์ซ์ ์คํธ๋ฆผ์ ํํฐ๋งํ์ฌ ์ง์๋ง ํฌํจํ๊ณ , ๊ทธ๋ค์ ์ ๊ณฑํ ๋ค์, ์ฒ์ 3๊ฐ์ ๊ฒฐ๊ณผ๋ง ๊ฐ์ ธ์ค๊ธฐ.
async function* generateNumbers(start) {
let i = start;
while (true) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i++;
}
}
async function processNumbers() {
const numbers = generateNumbers(1);
const processedNumbers = numbers
.filter(async (num) => num % 2 === 0)
.map(async (num) => num * num)
.take(3);
for await (const num of processedNumbers) {
console.log(num);
}
}
processNumbers();
์ค์ ์ฌ์ฉ ์ฌ๋ก: ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ ์์น์ ๋ฐ๋ผ ์ฌ์ฉ์๋ฅผ ํํฐ๋งํ๊ณ , ๊ด๋ จ ํ๋๋ง ํฌํจํ๋๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณํํ ๋ค์, ์ง๋์ ์ฒ์ 10๋ช ์ ์ฌ์ฉ์๋ฅผ ํ์ํฉ๋๋ค.
async function* fetchUsers() {
// ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ API์์ ์ฌ์ฉ์๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ ์๋ฎฌ๋ ์ด์
const users = [
{ id: 1, name: 'John Doe', location: 'New York', email: 'john.doe@example.com' },
{ id: 2, name: 'Jane Smith', location: 'London', email: 'jane.smith@example.com' },
{ id: 3, name: 'Ken Tan', location: 'Singapore', email: 'ken.tan@example.com' },
{ id: 4, name: 'Alice Jones', location: 'New York', email: 'alice.jones@example.com' },
{ id: 5, name: 'Bob Williams', location: 'London', email: 'bob.williams@example.com' },
{ id: 6, name: 'Siti Rahman', location: 'Singapore', email: 'siti.rahman@example.com' },
{ id: 7, name: 'Ahmed Khan', location: 'Dubai', email: 'ahmed.khan@example.com' },
{ id: 8, name: 'Maria Garcia', location: 'Madrid', email: 'maria.garcia@example.com' },
{ id: 9, name: 'Li Wei', location: 'Shanghai', email: 'li.wei@example.com' },
{ id: 10, name: 'Hans Mรผller', location: 'Berlin', email: 'hans.muller@example.com' },
{ id: 11, name: 'Emily Chen', location: 'Sydney', email: 'emily.chen@example.com' }
];
for (const user of users) {
await new Promise(resolve => setTimeout(resolve, 50));
yield user;
}
}
async function displayUsersOnMap(location, maxUsers) {
const users = fetchUsers();
const usersForMap = users
.filter(async (user) => user.location === location)
.map(async (user) => ({
id: user.id,
name: user.name,
location: user.location
}))
.take(maxUsers);
console.log(`Displaying up to ${maxUsers} users from ${location} on the map:`);
for await (const user of usersForMap) {
console.log(user);
}
}
// ์ฌ์ฉ ์์:
displayUsersOnMap('New York', 2);
displayUsersOnMap('London', 5);
ํด๋ฆฌํ ๋ฐ ๋ธ๋ผ์ฐ์ ์ง์
๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ์ ๋ํ ์ง์์ JavaScript ํ๊ฒฝ์ ๋ฐ๋ผ ๋ค๋ฅผ ์ ์์ต๋๋ค. ์ด์ ๋ธ๋ผ์ฐ์ ๋ ํ๊ฒฝ์ ์ง์ํด์ผ ํ๋ ๊ฒฝ์ฐ ํด๋ฆฌํ(polyfill)์ ์ฌ์ฉํด์ผ ํ ์ ์์ต๋๋ค. ํด๋ฆฌํ์ ๋๋ฝ๋ ๊ธฐ๋ฅ์ JavaScript๋ก ๊ตฌํํ์ฌ ์ ๊ณตํฉ๋๋ค. core-js์ ๊ฐ์ ์ฌ๋ฌ ํด๋ฆฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ์ ๋ํด ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
core-js ์ฌ์ฉ ์์ :
// ํ์ํ ํด๋ฆฌํ ๊ฐ์ ธ์ค๊ธฐ
require('core-js/features/async-iterator/map');
require('core-js/features/async-iterator/filter');
// ... ํ์ํ ๋ค๋ฅธ ํฌํผ ๊ฐ์ ธ์ค๊ธฐ
์ค๋ฅ ์ฒ๋ฆฌ
๋น๋๊ธฐ ์์
์ ๋ค๋ฃฐ ๋๋ ์ค๋ฅ๋ฅผ ์ ์ ํ๊ฒ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ์์๋ ํฌํผ์ ์ฌ์ฉ๋ ๋น๋๊ธฐ ํจ์ ๋ด์์ try...catch ๋ธ๋ก์ ์ฌ์ฉํ์ฌ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
์์ : map() ์์
๋ด์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ๋ ์ค๋ฅ ์ฒ๋ฆฌํ๊ธฐ.
async function* fetchData(urls) {
for (const url of urls) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
yield data;
} catch (error) {
console.error(`Error fetching data from ${url}: ${error}`);
yield null; // ๋๋ ์ค๋ฅ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ๋ฑ ์ ์ ํ๊ฒ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌ
}
}
}
async function processData() {
const urls = [
'https://api.example.com/data1',
'https://api.example.com/data2',
'https://api.example.com/data3'
];
const dataStream = fetchData(urls);
const processedData = dataStream.map(async (data) => {
if (data === null) {
return null; // ์ค๋ฅ ์ ํ
}
// ๋ฐ์ดํฐ ์ฒ๋ฆฌ
return data;
});
for await (const item of processedData) {
if (item === null) {
console.log('Skipping item due to error');
continue;
}
console.log('Processed Item:', item);
}
}
processData();
๋ชจ๋ฒ ์ฌ๋ก ๋ฐ ๊ณ ๋ ค ์ฌํญ
- ์ง์ฐ ํ๊ฐ(Lazy Evaluation): ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ๋ ์์ฒญ๋ ๋๋ง ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ์ง์ฐ ๋ฐฉ์์ผ๋ก ํ๊ฐ๋ฉ๋๋ค. ์ด๋ ํนํ ๋๊ท๋ชจ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ๋ค๋ฃฐ ๋ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
- ์ค๋ฅ ์ฒ๋ฆฌ: ํฌํผ์ ์ฌ์ฉ๋ ๋น๋๊ธฐ ํจ์ ๋ด์์๋ ํญ์ ์ค๋ฅ๋ฅผ ์ ์ ํ๊ฒ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
- ํด๋ฆฌํ: ์ด์ ๋ธ๋ผ์ฐ์ ๋ ํ๊ฒฝ์ ์ง์ํด์ผ ํ ๊ฒฝ์ฐ ํ์์ ๋ฐ๋ผ ํด๋ฆฌํ์ ์ฌ์ฉํ์ธ์.
- ๊ฐ๋ ์ฑ: ์ฝ๋๋ฅผ ๋ ์ฝ๊ธฐ ์ฝ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ข๊ฒ ๋ง๋ค๊ธฐ ์ํด ์ค๋ช ์ ์ธ ๋ณ์ ์ด๋ฆ๊ณผ ์ฃผ์์ ์ฌ์ฉํ์ธ์.
- ์ฑ๋ฅ: ์ฌ๋ฌ ํฌํผ๋ฅผ ํจ๊ป ์ฐ๊ฒฐํ ๋์ ์ฑ๋ฅ ์ํฅ์ ์ผ๋์ ๋์ธ์. ์ง์ฐ ๋ฐฉ์์ด ๋์์ด ๋์ง๋ง, ๊ณผ๋ํ ์ฐ๊ฒฐ์ ์ฌ์ ํ ์ค๋ฒํค๋๋ฅผ ์ ๋ฐํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
JavaScript ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ๋ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์์ฑ, ๋ณํ ๋ฐ ๊ด๋ฆฌํ๋ ๊ฐ๋ ฅํ๊ณ ์ฐ์ํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฌํ ํฌํผ๋ฅผ ํ์ฉํ์ฌ ๊ฐ๋ฐ์๋ค์ ๋ณต์กํ ๋น๋๊ธฐ ์์ ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋ ๊ฐ๊ฒฐํ๊ณ , ์ฝ๊ธฐ ์ฌ์ฐ๋ฉฐ, ์ ์ง๋ณด์ํ๊ธฐ ์ข์ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ์ ์ดํฐ๋ ์ดํฐ์ ๊ธฐ๋ณธ ์ฌํญ๊ณผ ๊ฐ ํฌํผ์ ๊ธฐ๋ฅ์ ์ดํดํ๋ ๊ฒ์ ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ด๋ฌํ ๋๊ตฌ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํ๋ , ์ค์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ , ๋น๋๊ธฐ API ์๋ต์ ๋ค๋ฃจ๋ , ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํฌํผ๋ ์ฝ๋๋ฅผ ํฌ๊ฒ ๋จ์ํํ๊ณ ์ ๋ฐ์ ์ธ ํจ์จ์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.